from dualpop import DualPop
import adapt
import converge
import population
import species
import net
import modify
import reproduce

# TODO: write it up to do the XOR-problem

def setup(problem):
    """Sets up the basic parameters and functions necessary for converging.
    """

    if not hasattr(problem, "process"):
        if not hasattr(problem, "errorfile_name"):
            problem.errorfile_name =  problem.__name__ + ".err"

        problem.errorfile = open(problem.errorfile_name, 'w')
        def print_process(error):
            print >> problem.errorfile, error
        problem.process = print_process

    if not hasattr(problem, "net_class"):
        problem.net_class = net.VectorNet

    class AdaptableEntry(problem.net_class, modify.Adaptable):
        def __init__(*args):
            problem.net_class.__init__(*args)
            modify.Adaptable.__init__(*args)

    problem.entry_class = AdaptableEntry

    def newEntry(*args):
        entry = problem.entry_class(*args)
        return entry

    species.newEntry = newEntry

    reproduce.DOMAIN = problem.domain

    if not hasattr(problem, "population"):
        problem.population = DualPop()

    if not hasattr(problem, "initial_popsize"):
        problem.initial_popsize = 100

    if not hasattr(problem, "initial_hid_size"):
        problem.initial_hid_size = (problem.domain.input_size + problem.domain.output_size) / 2

    init_l1 = [problem.domain.input_size, problem.initial_hid_size / 2,\
               problem.domain.output_size]
    init_l2 = [problem.domain.input_size, problem.initial_hid_size,\
               problem.domain.output_size]
    init_l3 = [problem.domain.input_size, problem.initial_hid_size * 2,\
               problem.domain.output_size]

    for i in xrange(problem.initial_popsize / 3 + 1):
        entry = newEntry(init_l1)
        problem.population.add(entry, problem.domain.getBatch().evaluate(entry))
        entry = newEntry(init_l2)
        problem.population.add(entry, problem.domain.getBatch().evaluate(entry))
        entry = newEntry(init_l3)
        problem.population.add(entry, problem.domain.getBatch().evaluate(entry))

    if not hasattr(problem, "converged"):
        if not hasattr(problem, "threshold"):
            problem.threshold = 0.01

        def defaultConverged():
            return problem.population.performance[0].value < problem.threshold

        problem.converged = defaultConverged

    def myadapt(examples):
        return adapt.adapt(examples, problem.population)

    return (problem.domain, myadapt, problem.converged)
